package com.zeng.ssm.service.support.trans.client.base;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.CharsetUtil;
import com.zeng.ssm.service.support.trans.GxpConstant;
import com.zeng.ssm.service.support.trans.TransConstant;
import com.zeng.ssm.service.support.trans.base.BaseClientHandler;
import com.zeng.ssm.service.support.trans.base.model.BaseMessage;
import com.zeng.ssm.service.support.trans.base.model.Head;
import com.zeng.ssm.service.support.trans.base.model.IBody;
import com.zeng.ssm.service.support.trans.base.model.Ret;
import com.zeng.ssm.util.DateUtil;
import com.zeng.ssm.util.TraceNoUtil;
import com.zeng.ssm.util.XStreamUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Optional;

/**
 * GXP客户端-Base类
 *
 * @author zengwanlin
 * @date 2023-09-01T10:12
 */
public abstract class BaseGxpClientHandler extends BaseClientHandler {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 组装请求报文
     */
    @Override
    protected void buildRequestMsg() {
        // 全局唯一流水号
        component.setReqSeqNo(createReqSeqNo());
        // 组装报文头
        Head head = buildHead();
        // 组装报文体
        IBody body = buildRequestBody();
        // 请求报文
        BaseMessage message = new BaseMessage();
        message.setHead(head);
        message.setBody(body);
        String reqMsg = XStreamUtil.toXml(message);
        reqMsg = String.format("%08d", reqMsg.getBytes(CharsetUtil.CHARSET_UTF_8).length) + reqMsg;

        component.setReqMsg(reqMsg);
    }

    /**
     * 发送报文
     */
    @Override
    protected void sendMsg() {
        // TODO 报文发送
        component.setRespMsg("<root><head><tranDate>20230904</tranDate><tranTime>101002</tranTime><ret><retCode>0000</retCode><retMsg>交易成功</retMsg></ret><respSeqNo>2023090410100100000235</respSeqNo></head><body><custNo>236783289054</custNo><custName>四川天府银行股份有限公司</custName><acctNo>234868340672364340968</acctNo><acctName>四川天府银行股份有限公司银行账户</acctName><acctType>201</acctType><availableAmt>237649072376.90</availableAmt></body></root>");
    }

    /**
     * 组装请求体
     *
     * @return
     */
    protected abstract IBody buildRequestBody();

    /**
     * 解析响应报文
     */
    @Override
    protected void parseResponseMsg() {
        BaseMessage respMessage = XStreamUtil.fromXml(component.getRespMsg(), BaseMessage.class, IBody.class, getResponseBodyClass());
        Head head = respMessage.getHead();
        Ret ret = Optional.ofNullable(head.getRet()).orElse(new Ret());
        if (GxpConstant.RET_CODE_0000.equals(ret.getRetCode())) {
            component.setSuccess(true);
            component.setRetCode(ret.getRetCode());
            component.setRetMsg(StringUtils.defaultString(ret.getRetMsg(), GxpConstant.RET_MSG_SUCCESS));
        } else {
            component.setSuccess(false);
            component.setRetCode(ret.getRetCode());
            component.setRetMsg(StringUtils.defaultString(ret.getRetMsg(), GxpConstant.RET_MSG_FAIL));
        }
        component.setRespSeqNo(head.getRespSeqNo());
        component.setRespMessage(respMessage);
    }

    /**
     * 获取响应实体类Class
     *
     * @return
     */
    protected abstract Class<? extends IBody> getResponseBodyClass();

    /**
     * 生成唯一流水号
     *
     * @return
     */
    private String createReqSeqNo() {
        int seqNoLen = 25;
        String dateTime = DateUtil.getDateTime();
        String seqNo = Long.toString(redisTemplate.opsForValue().increment(TransConstant.TRAN_SEQ_NO_KEY));
        if ((seqNoLen - dateTime.length()) < seqNo.length()) {
            redisTemplate.opsForValue().getOperations().delete(TransConstant.TRAN_SEQ_NO_KEY);
            seqNo = Long.toString(redisTemplate.opsForValue().increment(TransConstant.TRAN_SEQ_NO_KEY));
        }
        return DateUtil.getDateTime() + StringUtils.leftPad(seqNo, seqNoLen, "0");
    }

    /**
     * 组装报文头
     *
     * @return
     */
    protected Head buildHead() {
        Head head = new Head();
        head.setClientId(NetUtil.getLocalhostStr());
        head.setTranDate(this.tranDate);
        head.setTranTime(this.tranTime);
        head.setTraceNo(TraceNoUtil.getTraceNo());
        head.setReqSeqNo(component.getReqSeqNo());
        return head;
    }

}
